package com.se.nused;

import com.google.common.cache.*;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.log4j.Log4j2;

import java.time.Duration;

/**
 * Created by hdu_huang on 2019/1/6.
 */
@Log4j2
public class CacheTest {

    /**
    * @author hdu_huang
    * @date   2019/1/9
    * @desc   Cache 清除[淘汰/驱逐]策略
     *  1.size-based  2.timed eviction [不精准] 3.Reference-based Eviction 4.显示删除
     *   ***切记拿到缓存值之后不要在业务代码中对缓存直接做修改*** 引用
    */

    public static void main(String[] args) throws Exception{

        //UNIX Domain Socket
        googleCache();



    }

    // guava是进行get[不一定],put[主要]操作的时候顺便把元素回收的 与 redis,ehcache 另起线程不一样
    public static void googleCache() throws Exception{

        // expireAfterAccess[最后一次访问] 包含 expireAfterWrite[被创建或值被替换后]   refreshAfterWrite 只能使用在 LoadingCache 中

        Cache<String, Object> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .initialCapacity(2)
                .expireAfterWrite(Duration.ofMillis(3000))
                .expireAfterAccess(Duration.ofMillis(5000))
                .recordStats()
//                .removalListener(notification -> log.error("cause:{}, key:{}, value:{}", notification.getCause(), notification.getKey()))
                .concurrencyLevel(4)  //写入的最大线程数
                .build();


        cache.put("key1","value1");
        cache.put("key2","value2");
        cache.put("key3","value3");

        Object obj = cache.get("key1", () -> {
            //不能返回null
//            log.info("cache.get");
            return "Hello World!";
        });

        CacheStats stats = cache.stats();
        log.info(stats);
        log.info(obj);


        //maximumSize maximumWeight 不能同时生效 LRU
        // refreshAfterWrite 用户线程刷新[大量key刷新，阻塞很多用户线程] 可以重写reload，异步
        // 异步刷新所有线程返回旧值，后台线程刷新[reload]
        LoadingCache<String, Object> cache1 = CacheBuilder.newBuilder().maximumWeight(1000).<String, Object>weigher((key, value) -> key.length()).build(new CacheLoader<>() {
            @Override
            public Object load(String key) throws Exception {
                //数据库加载 load方法不能返回null
                return "liYun";
            }

            @Override //异步刷新
            public ListenableFuture<Object> reload(String key, Object oldValue) throws Exception {

                return super.reload(key, oldValue);
            }
        });


        cache1.put("hello", "world");
        log.info(cache1.get("hello1"));
        log.info(cache1.getUnchecked("hello1")); //load方法没有抛异常
    }
}
